<?php

/**
 * Базовый класс компонентов - объектов, принимающих в конструкторе произвольное
 * число открытых атрибутов.
 *
 */
abstract class Kernel_Component 
{

    /**
     * Сохраняет ли фильтр параметры для вложенных фильтров.
     *
     * @var boolean
     */
    protected $_through = false;

    /**
     * Значения сквозных параметров для вложенных фильтров.
     *
     * @var array
     */
    protected $_params = array();

    /**
     * Constructor.
     *
     * @var  array   $params
     */
    public function __construct($params = array()) 
    {
        $this->_setParams($params);
    }

    /**
     * Возвращает наименование компонента.
     *
     * @return string
     */
    protected function _getName() 
    {
        $class = get_class($this);
        return strtolower(substr($class, strrpos($class, '_') + 1));
    }

    /**
     * Устанавливает параметры компонента.
     *
     * @param  array    $params
     */
    private function _setParams($params) 
    {
        // свойства, указанные в определении класса
        $properties = get_class_vars(get_class($this));

        foreach ($params as $name => $value) {

            // свойство определено
            $defined = array_key_exists($name, $properties);

            // свойство открытое
            $public = 0 !== strpos($name, '_');

            switch (true) 
            {
                case $defined && $public:
                    // выставляем значение свойства объекта
                    $this->$name = $value;
                    break;

                case $public && $this->_through:
                    // запоминаем для вложенных фильтров
                    $this->_params[$name] = $value;
                    break;

                case !$defined:
                    $this->_param_error('Trying to set undefined property "' . $name . '"');
                    break;

                case !$public:
                    $this->_param_error('Trying to set non-public property "' . $name . '"');
                    break;

                default:
                    // этот случай в принципе должен быть невозможен, оставим
                    // для отладки
                    $this->_param_error('Unknown error with property "' . $name . '"');
                    break;
            }
        }
    }

    /**
     * Генерирует ошибку с указанным содержимым.
     *
     * @param   string  $contents
     */
    private function _param_error($contents) 
    {
        trigger_error(get_class($this) . ': ' . $contents, E_USER_ERROR);
    }
    
}
